{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from IPython.core.display import display, HTML\n",
    "display(HTML(\"<style>.container { width:80% !important; }</style>\"))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from IPython.display import HTML, IFrame\n",
    "display(IFrame(src = \"https://pandas.pydata.org/static/img/pydata_book.gif\", width=600, height=700))\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Material in this notebook is from the Appendix of:\n",
    "\n",
    "Python for Data Analysis\n",
    "Data Wrangling with Pandas, NumPy, and IPython\n",
    "By Wes McKinney\n",
    "Publisher: O'Reilly Media"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Exercises:\n",
    "\n",
    "http://www.w3resource.com/python-exercises/\n",
    "\n",
    "http://www.practicepython.org/\n",
    "\n",
    "http://codingbat.com/python"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Python Introduction"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Python is an interpreted language. \n",
    "\n",
    "The Python interpreter runs a program by executing\n",
    "one statement at a time. The standard interactive Python interpreter can be invoked on\n",
    "the command line with the python command:"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {},
   "source": [
    "C:\\Users\\tsusnjak>python\n",
    "Enthought Canopy Python 2.7.6 | 32-bit | (default, Jan 29 2014, 17:10:47) [MSC v.1500 32 bit (Intel)] on win32\n",
    "Type \"help\", \"copyright\", \"credits\" or \"license\" for more information.\n",
    ">>> a = 5\n",
    ">>> print a\n",
    "5"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {},
   "source": [
    "C:\\Users\\tsusnjak>python\n",
    "Enthought Canopy Python 2.7.6 | 32-bit | (default, Jan 29 2014, 17:10:47) [MSC v.1500 32 bit (Intel)] on win32\n",
    "Type \"help\", \"copyright\", \"credits\" or \"license\" for more information.\n",
    ">>> a = 5\n",
    ">>> print a\n",
    "5\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The >>> you see is the prompt where you’ll type expressions. To exit the Python interpreter\n",
    "and return to the command prompt, you can either type exit() or press Ctrl-D.\n",
    "Running Python programs is as simple as calling python with a .py file as its first argument.\n",
    "Suppose we had created hello_world.py with these contents:"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {},
   "source": [
    "print 'Hello world'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This can be run from the terminal simply as:"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {},
   "source": [
    "$ python hello_world.py\n",
    "Hello world"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "While many Python programmers execute all of their Python code in this way, many\n",
    "scientific Python programmers make use of IPython, an enhanced interactive Python\n",
    "interpreter. \n",
    "\n",
    "By using the %run command,\n",
    "IPython executes the code in the specified file in the same process, enabling you to\n",
    "explore the results interactively when it’s done."
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {},
   "source": [
    "C:\\Users\\tsusnjak>ipython\n",
    "Python 2.7.6 | 32-bit | (default, Jan 29 2014, 17:10:47) [MSC v.1500 32 bit (Intel)]\n",
    "Type \"copyright\", \"credits\" or \"license\" for more information.\n",
    "\n",
    "IPython 1.1.0 -- An enhanced Interactive Python.\n",
    "?         -> Introduction and overview of IPython's features.\n",
    "%quickref -> Quick reference.\n",
    "help      -> Python's own help system.\n",
    "object?   -> Details about 'object', use 'object??' for extra details.\n",
    "\n",
    "In [1]: %run hello_world.py\n",
    "Hello world\n",
    "\n",
    "In [2]:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The default IPython prompt adopts the numbered In [2]: style compared with the\n",
    "standard >>> prompt."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "# Jupyter Notebook Environment\n",
    "\n",
    "\n",
    "One considerable advantage that Python offers is a user-friendly interactive development environment. This environment is called the Jupyter Notebook. We will mostly be working in this environment during or lectures/workshops and you will also be completing your assignments in this environment.\n",
    "\n",
    "In order to start an Jupyter Notebook session, you will simply need to double click one of your notebooks (file extension .ipynb) and this will launch your default browser if 'jupyter-notebook.exe' is on the path. Otherwise, you can also drag the .ipynb file on to the executable.\n",
    "\n",
    "The Jupyter Notebook is a remarkable piece of technology. It is essentially an **interactive computational environment accessed through a web browser** (running on a local machine), which allows executable code to be combined with plots, images, mathematics and rich media.\n",
    "\n",
    "Its primary aim is to facilitate agile data analysis and exploratory computation. Its exceptional achievement is found in its ability to **support reproducible and verifiable research**, since all inputs and outputs may be stored in notebook documents.\n",
    "\n",
    "The notebook application runs as a lightweight server process on the command line. The actual notebooks running in a web browser are divided into 'cells'. Cells which have 'In []:' in front of them are as below are 'executable'. This means that if you press down the 'Shift' button and press 'Enter', the code that is in the adjacent sell will be executed and the output of that code will be displayed in a cell bellow.\n",
    "\n",
    "\n",
    "<img src=http://jupyter.org/assets/main-logo.svg width=400 height=500>\n",
    "\n",
    "\n",
    "\n",
    "The notebook server process can be started on the command line by running:"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {},
   "source": [
    "cd <file path to Anaconda3\\Scripts (likely C:\\ProgramData\\Anaconda3\\Scripts)>\n",
    "activate base\n",
    "jupyter-notebook.exe --notebook-dir=\"<absolute filepath to your notebooks folder>\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "On most platforms, your primary web browser will automatically open up to the notebook\n",
    "dashboard. In some cases you may have to navigate to the listed URL. From there,\n",
    "you can create a new notebook and start exploring."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Basics"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Language semantics"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The Python language design is distinguished by its emphasis on readability, simplicity,\n",
    "and explicitness. Some people go so far as to liken it to “executable pseudocode”.\n",
    "\n",
    "### **Indentation, not braces**\n",
    "\n",
    "Python uses whitespace indentation (tabs or spaces)to delimit blocks; this is termed the **off-side rule**.\n",
    "\n",
    "Take the for loop in the below quicksort algorithm:"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {},
   "source": [
    "for x in array:\n",
    "    if x < pivot:\n",
    "        less.append(x)\n",
    "    else:\n",
    "        greater.append(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A colon denotes the start of an indented code block after which all of the code must be\n",
    "indented by the same amount until the end of the block. In another language, you might\n",
    "instead have something like:"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {},
   "source": [
    "for x in array {\n",
    "    if x < pivot {\n",
    "        less.append(x)\n",
    "    } else {\n",
    "        greater.append(x)\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### **Everything is an object**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "An important characteristic of the Python language is the consistency of its object\n",
    "model. **Every number, string, data structure, function, class, module, and so on exists\n",
    "in the Python interpreter in its own “box” which is referred to as a Python object**. Each\n",
    "object has an associated type (for example, string or function) and internal data. In\n",
    "practice this makes the language very flexible, as even functions can be treated just like\n",
    "any other object."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# **Comments**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Any text preceded by the hash mark (pound sign) # is ignored by the Python interpreter.\n",
    "This is often used to add comments to code. At times you may also want to exclude\n",
    "certain blocks of code without deleting them. An easy solution is to comment out the\n",
    "code:"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {},
   "source": [
    "results = []\n",
    "for line in file_handle:\n",
    "    # keep the empty lines for now\n",
    "    # if len(line) == 0:\n",
    "    # continue\n",
    "    results.append(line.replace('foo', 'bar'))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Arithmetic Operators\n",
    "\n",
    "\n",
    "<table class=\"src\">\n",
    "<tbody><tr>\n",
    "<th style=\"width:5%\">Operator</th><th>Description</th><th>Example (If a = 10 and b = 20)</th>\n",
    "</tr>\n",
    "<tr>\n",
    "<td>+</td><td>Addition - Adds values on either side of the operator</td><td> a + b will give 30</td>\n",
    "</tr>\n",
    "<tr>\n",
    "<td>-</td><td>Subtraction - Subtracts right hand operand from left hand operand</td><td> a - b will give -10</td>\n",
    "</tr>\n",
    "<tr>\n",
    "<td>*</td><td>Multiplication - Multiplies values on either side of the operator</td><td> a * b will give 200</td>\n",
    "</tr>\n",
    "<tr>\n",
    "<td>/</td><td>Division - Divides left hand operand by right hand operand</td><td> b / a will give 2</td>\n",
    "</tr>\n",
    "<tr>\n",
    "<td>%</td><td>Modulus - Divides left hand operand by right hand operand and returns remainder</td><td> b % a will give 0</td>\n",
    "</tr>\n",
    "<tr>\n",
    "<td> ** </td><td>Exponent - Performs exponential (power) calculation on operators</td><td> a**b will give 10 to the power 20</td>\n",
    "</tr>\n",
    "<tr>\n",
    "<td>//</td><td>Floor Division - The division of operands where the result is the quotient in which the digits\n",
    "after the decimal point are removed.</td><td> 9//2 is equal to 4 and 9.0//2.0 is equal to 4.0</td>\n",
    "</tr>\n",
    "\n",
    "</tbody></table>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Scalar Types"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Python has a small set of built-in types for handling numerical data, strings, boolean\n",
    "(True or False) values, and dates and time. "
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {},
   "source": [
    "Type      Description\n",
    "\n",
    "None      The Python “null” value (only one instance of the None object exists)\n",
    "str       String type. ASCII-valued only in Python 2.x and Unicode in Python 3\n",
    "float     Double-precision (64-bit) floating point number. Note there is no separate double type.\n",
    "bool      A True or False value\n",
    "int       Signed integer with maximum value determined by the platform."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Summary of all Python 3's built-in types^\n",
    "\n",
    "^ Source: https://en.wikipedia.org/wiki/Python_(programming_language)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<tbody><tr>\n",
    "<th>Type\n",
    "</th>\n",
    "<th><a href=\"/wiki/Immutable_object\" title=\"Immutable object\">Mutability</a>\n",
    "</th>\n",
    "<th>Description\n",
    "</th>\n",
    "<th style=\"width: 23em;\">Syntax examples\n",
    "</th></tr>\n",
    "<tr>\n",
    "<td><code>bool</code>\n",
    "</td>\n",
    "<td>immutable\n",
    "</td>\n",
    "<td><a href=\"/wiki/Boolean_value\" class=\"mw-redirect\" title=\"Boolean value\">Boolean value</a>\n",
    "</td>\n",
    "<td><code class=\"mw-highlight\" id=\"\" style=\"\" dir=\"ltr\"><span class=\"bp\">True</span></code><br><code class=\"mw-highlight\" id=\"\" style=\"\" dir=\"ltr\"><span class=\"kc\">False</span></code>\n",
    "</td></tr>\n",
    "<tr>\n",
    "<td><code>bytearray</code>\n",
    "</td>\n",
    "<td>mutable\n",
    "</td>\n",
    "<td>Sequence of <a href=\"/wiki/Byte\" title=\"Byte\">bytes</a>\n",
    "</td>\n",
    "<td><code class=\"mw-highlight\" id=\"\" style=\"\" dir=\"ltr\"><span class=\"nb\">bytearray</span><span class=\"p\">(</span><span class=\"sa\">b</span><span class=\"s1\">'Some ASCII'</span><span class=\"p\">)</span></code><br><code class=\"mw-highlight\" id=\"\" style=\"\" dir=\"ltr\"><span class=\"nb\">bytearray</span><span class=\"p\">(</span><span class=\"sa\">b</span><span class=\"s2\">\"Some ASCII\"</span><span class=\"p\">)</span></code><br><code class=\"mw-highlight\" id=\"\" style=\"\" dir=\"ltr\"><span class=\"nb\">bytearray</span><span class=\"p\">([</span><span class=\"mi\">119</span><span class=\"p\">,</span> <span class=\"mi\">105</span><span class=\"p\">,</span> <span class=\"mi\">107</span><span class=\"p\">,</span> <span class=\"mi\">105</span><span class=\"p\">])</span></code>\n",
    "</td></tr>\n",
    "<tr>\n",
    "<td><code>bytes</code>\n",
    "</td>\n",
    "<td>immutable\n",
    "</td>\n",
    "<td>Sequence of bytes\n",
    "</td>\n",
    "<td><code class=\"mw-highlight\" id=\"\" style=\"\" dir=\"ltr\"><span class=\"sa\">b</span><span class=\"s1\">'Some ASCII'</span></code><br><code class=\"mw-highlight\" id=\"\" style=\"\" dir=\"ltr\"><span class=\"sa\">b</span><span class=\"s2\">\"Some ASCII\"</span></code><br><code class=\"mw-highlight\" id=\"\" style=\"\" dir=\"ltr\"><span class=\"nb\">bytes</span><span class=\"p\">([</span><span class=\"mi\">119</span><span class=\"p\">,</span> <span class=\"mi\">105</span><span class=\"p\">,</span> <span class=\"mi\">107</span><span class=\"p\">,</span> <span class=\"mi\">105</span><span class=\"p\">])</span></code>\n",
    "</td></tr>\n",
    "<tr>\n",
    "<td><code>complex</code>\n",
    "</td>\n",
    "<td>immutable\n",
    "</td>\n",
    "<td><a href=\"/wiki/Complex_number\" title=\"Complex number\">Complex number</a> with real and imaginary parts\n",
    "</td>\n",
    "<td><code class=\"mw-highlight\" id=\"\" style=\"\" dir=\"ltr\"><span class=\"mi\">3</span><span class=\"o\">+</span><span class=\"mf\">2.7</span><span class=\"n\">j</span></code>\n",
    "</td></tr>\n",
    "<tr>\n",
    "<td><code>dict</code>\n",
    "</td>\n",
    "<td>mutable\n",
    "</td>\n",
    "<td><a href=\"/wiki/Associative_array\" title=\"Associative array\">Associative array</a> (or dictionary) of key and value pairs; can contain mixed types (keys and values), keys must be a hashable type\n",
    "</td>\n",
    "<td><code class=\"mw-highlight\" id=\"\" style=\"\" dir=\"ltr\"><span class=\"p\">{</span><span class=\"s1\">'key1'</span><span class=\"p\">:</span> <span class=\"mf\">1.0</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">:</span> <span class=\"bp\">False</span><span class=\"p\">}</span></code><br><code class=\"mw-highlight\" id=\"\" style=\"\" dir=\"ltr\"><span class=\"p\">{}</span></code>\n",
    "</td></tr>\n",
    "<tr>\n",
    "<td><code>ellipsis</code><sup class=\"reference plainlinks nourlexpansion\" id=\"ref_inaccessible-type\"><a href=\"#endnote_inaccessible-type\">a</a></sup>\n",
    "</td>\n",
    "<td>immutable\n",
    "</td>\n",
    "<td>An <a href=\"/wiki/Ellipsis_(programming_operator)\" class=\"mw-redirect\" title=\"Ellipsis (programming operator)\">ellipsis</a> placeholder to be used as an index in <a href=\"/wiki/NumPy\" title=\"NumPy\">NumPy</a> arrays\n",
    "</td>\n",
    "<td><code class=\"mw-highlight\" id=\"\" style=\"\" dir=\"ltr\"><span class=\"o\">...</span></code><br><code class=\"mw-highlight\" id=\"\" style=\"\" dir=\"ltr\"><span class=\"bp\">Ellipsis</span></code>\n",
    "</td></tr>\n",
    "<tr>\n",
    "<td><code>float</code>\n",
    "</td>\n",
    "<td>immutable\n",
    "</td>\n",
    "<td><a href=\"/wiki/Double_precision\" class=\"mw-redirect\" title=\"Double precision\">Double precision</a> <a href=\"/wiki/Floating_point\" class=\"mw-redirect\" title=\"Floating point\">floating point</a> number. The precision is machine dependent but in practice is 64 bits.<sup class=\"noprint Inline-Template Template-Fact\" style=\"white-space:nowrap;\">[<i><a href=\"/wiki/Wikipedia:Citation_needed\" title=\"Wikipedia:Citation needed\"><span title=\"This claim needs references to reliable sources. (December 2019)\">citation needed</span></a></i>]</sup>\n",
    "</td>\n",
    "<td><code class=\"mw-highlight\" id=\"\" style=\"\" dir=\"ltr\"><span class=\"mf\">3.1415927</span></code>\n",
    "</td></tr>\n",
    "<tr>\n",
    "<td><code>frozenset</code>\n",
    "</td>\n",
    "<td>immutable\n",
    "</td>\n",
    "<td>Unordered <a href=\"/wiki/Set_(computer_science)\" class=\"mw-redirect\" title=\"Set (computer science)\">set</a>, contains no duplicates; can contain mixed types, if hashable\n",
    "</td>\n",
    "<td><code class=\"mw-highlight\" id=\"\" style=\"\" dir=\"ltr\"><span class=\"nb\">frozenset</span><span class=\"p\">([</span><span class=\"mf\">4.0</span><span class=\"p\">,</span> <span class=\"s1\">'string'</span><span class=\"p\">,</span> <span class=\"bp\">True</span><span class=\"p\">])</span></code>\n",
    "</td></tr>\n",
    "<tr>\n",
    "<td><code>int</code>\n",
    "</td>\n",
    "<td>immutable\n",
    "</td>\n",
    "<td><a href=\"/wiki/Integer_(computer_science)\" title=\"Integer (computer science)\">Integer</a> of unlimited magnitude<sup id=\"cite_ref-pep0237_85-0\" class=\"reference\"><a href=\"#cite_note-pep0237-85\">[85]</a></sup>\n",
    "</td>\n",
    "<td><code class=\"mw-highlight\" id=\"\" style=\"\" dir=\"ltr\"><span class=\"mi\">42</span></code>\n",
    "</td></tr>\n",
    "<tr>\n",
    "<td><code>list</code>\n",
    "</td>\n",
    "<td>mutable\n",
    "</td>\n",
    "<td><a href=\"/wiki/List_(computer_science)\" class=\"mw-redirect\" title=\"List (computer science)\">List</a>, can contain mixed types\n",
    "</td>\n",
    "<td><code class=\"mw-highlight\" id=\"\" style=\"\" dir=\"ltr\"><span class=\"p\">[</span><span class=\"mf\">4.0</span><span class=\"p\">,</span> <span class=\"s1\">'string'</span><span class=\"p\">,</span> <span class=\"kc\">True</span><span class=\"p\">]</span></code><br><code class=\"mw-highlight\" id=\"\" style=\"\" dir=\"ltr\"><span class=\"p\">[]</span></code>\n",
    "</td></tr>\n",
    "<tr>\n",
    "<td><code>NoneType</code><sup class=\"reference plainlinks nourlexpansion\" id=\"ref_inaccessible-type\"><a href=\"#endnote_inaccessible-type\">a</a></sup>\n",
    "</td>\n",
    "<td>immutable\n",
    "</td>\n",
    "<td>An object representing the absence of a value, often called <a href=\"/wiki/Null_pointer\" title=\"Null pointer\">Null</a> in other languages\n",
    "</td>\n",
    "<td><code class=\"mw-highlight\" id=\"\" style=\"\" dir=\"ltr\"><span class=\"kc\">None</span></code>\n",
    "</td></tr>\n",
    "<tr>\n",
    "<td><code>NotImplementedType</code><sup class=\"reference plainlinks nourlexpansion\" id=\"ref_inaccessible-type\"><a href=\"#endnote_inaccessible-type\">a</a></sup>\n",
    "</td>\n",
    "<td>immutable\n",
    "</td>\n",
    "<td>A placeholder that can be returned from <a href=\"/wiki/Operator_overloading\" title=\"Operator overloading\">overloaded operators</a> to indicate unsupported operand types.\n",
    "</td>\n",
    "<td><code class=\"mw-highlight\" id=\"\" style=\"\" dir=\"ltr\"><span class=\"bp\">NotImplemented</span></code>\n",
    "</td></tr>\n",
    "<tr>\n",
    "<td><code>range</code>\n",
    "</td>\n",
    "<td>immutable\n",
    "</td>\n",
    "<td>A Sequence of numbers commonly used for looping specific number of times in <code>for</code> loops<sup id=\"cite_ref-86\" class=\"reference\"><a href=\"#cite_note-86\">[86]</a></sup>\n",
    "</td>\n",
    "<td><code class=\"mw-highlight\" id=\"\" style=\"\" dir=\"ltr\"><span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"mi\">10</span><span class=\"p\">)</span></code><br><code class=\"mw-highlight\" id=\"\" style=\"\" dir=\"ltr\"><span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"mi\">10</span><span class=\"p\">,</span> <span class=\"o\">-</span><span class=\"mi\">5</span><span class=\"p\">,</span> <span class=\"o\">-</span><span class=\"mi\">2</span><span class=\"p\">)</span></code>\n",
    "</td></tr>\n",
    "<tr>\n",
    "<td><code>set</code>\n",
    "</td>\n",
    "<td>mutable\n",
    "</td>\n",
    "<td>Unordered <a href=\"/wiki/Set_(computer_science)\" class=\"mw-redirect\" title=\"Set (computer science)\">set</a>, contains no duplicates; can contain mixed types, if hashable\n",
    "</td>\n",
    "<td><code class=\"mw-highlight\" id=\"\" style=\"\" dir=\"ltr\"><span class=\"p\">{</span><span class=\"mf\">4.0</span><span class=\"p\">,</span> <span class=\"s1\">'string'</span><span class=\"p\">,</span> <span class=\"kc\">True</span><span class=\"p\">}</span></code><br><code class=\"mw-highlight\" id=\"\" style=\"\" dir=\"ltr\"><span class=\"nb\">set</span><span class=\"p\">()</span></code>\n",
    "</td></tr>\n",
    "<tr>\n",
    "<td><code>str</code>\n",
    "</td>\n",
    "<td>immutable\n",
    "</td>\n",
    "<td>A <a href=\"/wiki/String_(computer_science)\" title=\"String (computer science)\">character string</a>: sequence of Unicode codepoints\n",
    "</td>\n",
    "<td><code class=\"mw-highlight\" id=\"\" style=\"\" dir=\"ltr\"><span class=\"s1\">'Wikipedia'</span></code><br><code class=\"mw-highlight\" id=\"\" style=\"\" dir=\"ltr\"><span class=\"s2\">\"Wikipedia\"</span></code><br><div class=\"mw-highlight mw-content-ltr\" dir=\"ltr\"><pre><span></span><span class=\"sd\">\"\"\"Spanning</span>\n",
    "<span class=\"sd\">multiple</span>\n",
    "<span class=\"sd\">lines\"\"\"</span>\n",
    "</pre></div>\n",
    "</td></tr>\n",
    "<tr>\n",
    "<td><code>tuple</code>\n",
    "</td>\n",
    "<td>immutable\n",
    "</td>\n",
    "<td>Can contain mixed types\n",
    "</td>\n",
    "<td><code class=\"mw-highlight\" id=\"\" style=\"\" dir=\"ltr\"><span class=\"p\">(</span><span class=\"mf\">4.0</span><span class=\"p\">,</span> <span class=\"s1\">'string'</span><span class=\"p\">,</span> <span class=\"kc\">True</span><span class=\"p\">)</span></code><br><code class=\"mw-highlight\" id=\"\" style=\"\" dir=\"ltr\"><span class=\"p\">(</span><span class=\"s1\">'single element'</span><span class=\"p\">,)</span></code><br><code class=\"mw-highlight\" id=\"\" style=\"\" dir=\"ltr\"><span class=\"p\">()</span></code>\n",
    "</td></tr></tbody>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## **Numeric types**\n",
    "\n",
    "The primary Python types for numbers are int and float. The size of the integer which\n",
    "can be stored as an int is dependent on your platform (whether 32 or 64-bit), but Python\n",
    "will transparently convert a very large integer to long, which can store arbitrarily large\n",
    "integers."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ival = 17239871\n",
    "ival ** 6"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Floating point numbers are represented with the Python float type. Under the hood\n",
    "each one is a double-precision (64 bits) value.\n",
    "\n",
    "In Python 3, two ints in a division will return a float (tis is different to Python 2 where two ints in a division will return an int ):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "3 / 2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To get C-style integer division (which drops the fractional part if the result is not a\n",
    "whole number), use the floor division operator //:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "3 // 2.0"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## **Dynamic references, strong types**\n",
    "\n",
    "Python is a **dynamically-typed language**. In contrast with many compiled languages, such as Java and C++, object references in\n",
    "Python have no type associated with them. \n",
    "\n",
    "An assignment statement in Python creates new variables and gives them values.\n",
    "\n",
    "There is no problem with the following:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = 5"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In Python the assignment, using the above, translates to \"(generic) name *a* receives a reference to a separate, dynamically allocated object of numeric (int) type of value 5.\" \n",
    "\n",
    "This is referred to as \"binding\" the name to the object. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "type(a)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = 'blah'\n",
    "type(a)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Variables are names for objects within a particular namespace; the type information is\n",
    "stored in the object itself. \n",
    "\n",
    "Some observers might hastily conclude that Python is not a\n",
    "**“typed language”**. This is not true; consider this example:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "'5' + 5"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In some languages, such as Visual Basic, the string '5' might get implicitly converted\n",
    "(or casted) to an integer, thus yielding 10. Yet in other languages, such as JavaScript,\n",
    "the integer 5 might be casted to a string, yielding the concatenated string '55'. \n",
    "\n",
    "In this\n",
    "regard **Python is also considered a strongly-typed language**, which means that every object\n",
    "has a specific type (or class), and implicit conversions will occur only in certain obvious\n",
    "circumstances, such as the following:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = 4.5\n",
    "b = 2\n",
    "\n",
    "# String formatting\n",
    "'a is %s, b is %s' % (type(a), type(b))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "'a is {}, b is {}'.format(type(a), type(b))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a / b"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Knowing the type of an object is important, and it’s useful to be able to write functions that can handle many different kinds of input. You can check that an object is an instance of a particular type using the isinstance function:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = 5\n",
    "isinstance(a, int)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "isinstance can accept a tuple (more on tuples later) of types if you want to check that an object’s type is\n",
    "among those present in the tuple:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = 5; b = 4.5"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "isinstance(a, (int, float))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "isinstance(b, (int, float))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Functions"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Functions are the primary and most important method of code organization and reuse\n",
    "in Python. \n",
    "\n",
    "There probably isn't such a thing as having too many functions. In fact, I would\n",
    "argue that most programmers doing data analysis don’t write enough functions! \n",
    "\n",
    "Functions are declared using the **def** keyword\n",
    "and returned from using the **return** keyword:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def my_function(x, y, z=1.5):\n",
    "    if z > 1:\n",
    "        return z * (x + y)\n",
    "    else:\n",
    "        return z / (x + y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "There is no issue with having **multiple return statements**. If the end of a function is\n",
    "reached without encountering a return statement, **None** is returned.\n",
    "\n",
    "Each function can have some number of **positional arguments** and some number of\n",
    "**keyword arguments**. Keyword arguments are most commonly used to specify default\n",
    "values or optional arguments. In the above function, x and y are positional arguments\n",
    "while z is a keyword argument. This means that it can be called in either of these\n",
    "equivalent ways:"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {},
   "source": [
    "my_function(5, 6, z=0.7)\n",
    "my_function(3.14, 7, 3.5)\n",
    "my_function(3.14, 7)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The main restriction on function arguments it that the **keyword arguments must follow\n",
    "the positional arguments** (if any). \n",
    "\n",
    "**You can specify keyword arguments in any order**;\n",
    "this frees you from having to remember which order the function arguments were\n",
    "specified in and only what their names are."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Almost every object in Python has attached functions, known as methods, that have\n",
    "access to the object’s internal contents. \n",
    "\n",
    "They can be called using the syntax:"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {},
   "source": [
    "obj.some_method(x, y, z)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### **Exercise**:\n",
    "\n",
    "Write a function that finds the Max of three numbers."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#your code here:\n",
    "def my_max(\n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "my_max(4,5,2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Functions and pass-by-reference Python style: pass-by-object-reference"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "When assigning a variable (or name) in Python, you are creating a reference to the object on the right hand side of the equals sign. \n",
    "\n",
    "In practical terms, consider a list (more on lists later) of integers:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = [1, 2, 3]\n",
    "a"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Suppose we assign *a* to a new variable *b*:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "b = a"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In some languages, this assignment would cause the data [1, 2, 3] to be copied. In\n",
    "Python, *a* and *b* actually now refer to the same object, the original list [1, 2, 3]\n",
    "\n",
    "You can prove this to yourself by appending an element to\n",
    "*a* and then examining b:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a.append(4)\n",
    "b"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "b.append(5)\n",
    "a"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "What if we decide to change the object reference by assigning something different to b?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "b = 'hmmm...what does this do to a?'\n",
    "a"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**In this instance, a new memory location is created for *b***."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Understanding the semantics of references in Python and when, how, and why data is\n",
    "copied is especially critical when working with larger data sets in Python."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**When you pass objects as arguments to a function, you are passing object references; no\n",
    "copying occurs**. \n",
    "\n",
    "This means that **a function can mutate the internals of its arguments** ie the objects that they point to. \n",
    "\n",
    "Suppose we had the following function:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def append_element(some_list, element):\n",
    "    some_list.append(element)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Then given what’s been said, this should not come as a surprise:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "data = [1, 2, 3]\n",
    "append_element(data, 4)\n",
    "data"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "However, **attempting to change the actual reference object in the function will result in a new memory location being created** and the callee object remaining unaltered:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def change_object_reference(some_list):\n",
    "    some_list = [10, 9, 8]\n",
    "    \n",
    "data = [1, 2, 3]\n",
    "change_object_reference(data)\n",
    "data"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Object state/contents is mutable when passed to functions, but the memory location is not.**\n",
    "\n",
    "If you need object references changed, then wrap them up in another object and pass them to a function.\n",
    "\n",
    "Python's argument passing model is sometimes called pass-by-object-reference, but is in essence pass-by-reference whereby the reference is passed by value."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Namespaces, Scope, and Local Functions"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Functions can access variables in two different scopes: **global** and **local**. \n",
    "\n",
    "An alternate\n",
    "and more descriptive name describing a variable scope in Python is a **namespace**. \n",
    "\n",
    "Any\n",
    "variables that are assigned within a function by default are assigned to the local namespace.\n",
    "The local namespace is created when the function is called and immediately\n",
    "populated by the function’s arguments. \n",
    "\n",
    "After the function is finished, the local namespace\n",
    "is destroyed (with some exceptions, see section on closures below). Consider the\n",
    "following function:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def func():\n",
    "    a = []\n",
    "    for i in [1,2,3,4,5]:\n",
    "        a.append(i)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Upon calling func(), the empty list a is created, 5 elements are appended, then *a* is\n",
    "destroyed when the function exits. \n",
    "\n",
    "Suppose instead we had declared *a* outside of the function:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = []\n",
    "def func():\n",
    "    for i in [1,2,3,4,5]:\n",
    "        a.append(i)\n",
    "        \n",
    "func()\n",
    "a"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now suppose we tried to change the object reference for *a*\n",
    "inside the function:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = []\n",
    "def func2():\n",
    "    a = 'interesting...'\n",
    "    print(a)\n",
    "    \n",
    "func2()\n",
    "print(a)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Assigning to global variables within a function is possible, but those variables must be\n",
    "declared as global using the global keyword:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = None\n",
    "print(a)\n",
    "def bind_a_variable():\n",
    "    global a\n",
    "    a = [1,2]\n",
    "    \n",
    "bind_a_variable()\n",
    "print(a)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "I generally discourage people from using the global keyword frequently.\n",
    "Typically global variables are used to store some kind of state in a system.\n",
    "If you find yourself using a lot of them, it’s probably a sign that\n",
    "some object-oriented programming (using classes) is in order."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Functions can be declared anywhere, and there is no problem with having local functions\n",
    "that are dynamically created when a function is called:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def outer_function(x, y, z):\n",
    "    def inner_function(a, b, c):\n",
    "        pass\n",
    "    pass\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In the above code, the inner_function will not exist until outer_function is called. As\n",
    "soon as outer_function is done executing, the inner_function is destroyed.\n",
    "\n",
    "Nested inner functions can access the local namespace of the enclosing function.\n",
    "\n",
    "In a strict sense, all functions are local to some scope, that scope may just be the module\n",
    "level scope."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Returning Multiple Values"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "When I first programmed in Python after having programmed in C and C++, one of\n",
    "my favorite features was the ability to return multiple values from a function. Here’s a\n",
    "simple example:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def f():\n",
    "    a = 5\n",
    "    b = 6\n",
    "    c = 7\n",
    "    \n",
    "    return a, b, c\n",
    "\n",
    "a, b, c = f()\n",
    "a"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In data analysis and other scientific applications, you will likely find yourself doing this\n",
    "very often as **many functions may have multiple outputs**, whether those are data structures\n",
    "or other auxiliary data computed inside the function. \n",
    "\n",
    "If you think about tuple\n",
    "packing and unpacking, you will later realize that what’s happening\n",
    "here is that the function is actually just returning one object, namely a tuple,\n",
    "which is then being unpacked into the result variables. \n",
    "\n",
    "In the above example, we could\n",
    "have done instead:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "return_value = f()\n",
    "return_value"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In this case, return_value would be, as you may guess, a 3-tuple with the three returned\n",
    "variables. A potentially attractive alternative to returning multiple values like above\n",
    "might be to return a dict (more on dictionaries later) instead:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def f():\n",
    "    a = 5\n",
    "    b = 6\n",
    "    c = 7\n",
    "    \n",
    "    return {'a' : a, 'b' : b, 'c' : c}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# **Attributes and methods** (Object-Oriented Programming)\n",
    "\n",
    "Objects in Python typically have both **attributes** (other Python objects stored “inside”\n",
    "the object) and **methods**, functions associated with an object which can have access to\n",
    "the object’s internal data. \n",
    "\n",
    "Both of them are accessed via the syntax obj.attribute_name:"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {},
   "source": [
    "In [1]: a = 'foo'\n",
    "In [2]: a.<Tab>\n",
    "a.capitalize a.format a.isupper a.rindex a.strip\n",
    "a.center a.index a.join a.rjust a.swapcase\n",
    "a.count a.isalnum a.ljust a.rpartition a.title\n",
    "a.decode a.isalpha a.lower a.rsplit a.translate\n",
    "a.encode a.isdigit a.lstrip a.rstrip a.upper\n",
    "a.endswith a.islower a.partition a.split a.zfill\n",
    "a.expandtabs a.isspace a.replace a.splitlines\n",
    "a.find a.istitle a.rfind a.startswith"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Rules for naming variables\n",
    "\n",
    "Every language has rules for naming variables. The rules in Python are the following:\n",
    "\n",
    "A valid variable name is a non-empty sequence of characters of any length with:\n",
    "\n",
    "   1. the start character can be the underscore \"_\" or a capital or lower case letter\n",
    "   2. the letters following the start character can be anything which is permitted as a start character plus the digits.\n",
    "   3. Just a warning for Windows-spoilt users: variable names are case-sensitive\n",
    "   4. Python keywords are not allowed as variable names\n",
    "\n",
    "\n",
    "<p>The following list shows the keywords in Python. These reserved words may not be used as constant or variable or any other identifier names.</p>\n",
    "<table class=\"src\">\n",
    "<th>\n",
    "<tr><td>and</td><td>exec</td><td>not</td></tr>\n",
    "<tr><td>assert</td><td>finally</td><td>or</td></tr>\n",
    "<tr><td>break</td><td>for</td><td>pass</td></tr>\n",
    "<tr><td>class</td><td>from</td><td>print</td></tr>\n",
    "<tr><td>continue</td><td>global</td><td>raise</td></tr>\n",
    "<tr><td>def</td><td>if</td><td>return</td></tr>\n",
    "<tr><td>del</td><td>import</td><td>try</td></tr>\n",
    "<tr><td>elif</td><td>in</td><td>while</td></tr>\n",
    "<tr><td>else</td><td>is</td><td>with </td></tr>\n",
    "<tr><td>except</td><td>lambda</td><td>yield</td></tr>\n",
    "<th>\n",
    "</table>\n",
    "\n",
    "\n",
    "In terms of coding conventions and styel, stick to PEP 8 as much as possible: https://www.python.org/dev/peps/pep-0008/\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Control Flow and Logic Operators\n",
    "\n",
    "<img src=http://www.principledpolicy.com/wp-content/uploads/2010/10/logic.jpg width=500>\n",
    "\n",
    "<table class=\"src\">\n",
    "<tbody><tr>\n",
    "<th style=\"width:5%\">Operator</th><th>Description</th><th>Example (If a = 10 and b = 20)</th>\n",
    "</tr>\n",
    "\n",
    "<tr>\n",
    "<td>==</td><td> Checks if the value of two operands are equal or not, if yes then condition becomes true.</td><td> (a == b) is not true. </td>\n",
    "</tr>\n",
    "<tr>\n",
    "<td>!=</td><td> Checks if the value of two operands are equal or not, if values are not equal then condition becomes true.</td><td> (a != b) is true. </td>\n",
    "</tr>\n",
    "<tr>\n",
    "<td>&gt;</td><td> Checks if the value of left  operand is greater than the value of right operand, if yes then condition becomes true.</td><td> (a &gt; b) is not true. </td>\n",
    "</tr>\n",
    "<tr>\n",
    "<td>&lt;</td><td> Checks if the value of left  operand is less than the value of right operand, if yes then condition becomes true.</td><td> (a &lt; b) is true. </td>\n",
    "</tr>\n",
    "<tr>\n",
    "<td>&gt;=</td><td> Checks if the value of left  operand is greater than or equal to the value of right operand, if yes then condition becomes true.</td><td> (a &gt;= b) is not true. </td>\n",
    "</tr>\n",
    "<tr>\n",
    "<td>&lt;=</td><td> Checks if the value of left  operand is less than or equal to the value of right operand, if yes then condition becomes true.</td><td> (a &lt;= b) is true. </td>\n",
    "</tr>\n",
    "<th>\n",
    "</tbody></table>\n",
    "\n",
    "\n",
    "\n",
    "<img src=http://calwatchdog.com/wp-content/uploads/2013/05/Spock-logic-300x240.jpg >\n",
    "\n",
    "\n",
    "Logical operators enable us to construct more complex boolean expressions.\n",
    "\n",
    "<table class=\"src\">\n",
    "<tbody><tr>\n",
    "<th style=\"width:5%\">Operator</th><th>Description</th><th>Example (If a = True and b = True)</th>\n",
    "\n",
    "</tr>\n",
    "\n",
    "<tr>\n",
    "<td>and</td><td> Called Logical AND  operator. If both the operands are true then then condition becomes true.</td><td> (a and b) is true.</td>\n",
    "</tr>\n",
    "<tr>\n",
    "<td>or</td><td>Called Logical OR Operator.  If any of the two operands are non zero then then condition becomes true.</td><td> (a or b) is true.</td>\n",
    "</tr>\n",
    "<tr><td>not</td><td>Called Logical NOT Operator.  Use to reverses the logical state of its operand. If a condition is true then Logical NOT operator will make false.</td><td> not(a and b) is false. </td>\n",
    "</tr>\n",
    "<th>\n",
    "</tbody>\n",
    "</table>\n",
    "\n",
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# **Binary operators and comparisons**\n",
    "\n",
    "Most of the binary math operations and comparisons are as you might expect."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "5 >= 2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To check if two references refer to the same object, use the **is** keyword. **is not** is also\n",
    "perfectly valid if you want to check that two objects are not the same:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = [1, 2, 3]\n",
    "b = a\n",
    "a is b"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Note, the list function always creates a new list\n",
    "c = list(a)\n",
    "print(c)\n",
    "a is not c"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note this is not the same thing is comparing with ==, because in this case we have:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a == c"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In the above, the actual contents are being compared, which are in this case the same, though the objects are different (two different memory locations are involved)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A very common use of **is** and **is not** is to check if a variable is **None**, since there is only one instance of **None**:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = None\n",
    "a is None"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# **if, elif, and else**\n",
    "\n",
    "The if statement is one of the most well-known control flow statement types. It checks\n",
    "a condition which, if True, evaluates the code in the block that follows:"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {},
   "source": [
    "if x < 0:\n",
    "    print \"It's negative\"    "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "An if statement can be optionally followed by one or more elif (contraction for *else if*) blocks and a catch-all\n",
    "else block if all of the conditions are False:"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {},
   "source": [
    "if x < 0:\n",
    "    print 'It's negative'\n",
    "elif x == 0:\n",
    "    print 'Equal to zero'\n",
    "elif 0 < x < 5:\n",
    "    print 'Positive but smaller than 5'\n",
    "else:\n",
    "    print 'Positive and larger than or equal to 5'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If any of the conditions is True, no further elif or else blocks will be reached. With a\n",
    "compound condition using and or or, conditions are evaluated left-to-right and will\n",
    "short circuit:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = 5; b = 7\n",
    "c = 8; d = 4\n",
    "\n",
    "if a < b or c > d:\n",
    "    print('Made it')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In this example, the comparison c > d never gets evaluated because the first comparison\n",
    "was True."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### **Exercise**: \n",
    "\n",
    "Write a function that takes three integers and returns their sum. However, if two values are equal sum will be zero."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def sum_it(x, y, z):\n",
    "    "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# **for loops**\n",
    "\n",
    "for loops are for iterating over a collection (like a list or tuple) or an iterator. The\n",
    "standard syntax for a for loop is:"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {},
   "source": [
    "for value in collection:\n",
    "    # do something with value"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A for loop can be advanced to the next iteration, skipping the remainder of the block,\n",
    "using the continue keyword. Consider this code which sums up integers in a list and\n",
    "skips None values:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "sequence = [1, 2, None, 4, None, 5]\n",
    "total = 0\n",
    "\n",
    "for value in sequence:\n",
    "    print(value)\n",
    "    if value is None:\n",
    "        continue\n",
    "    total += value\n",
    "    \n",
    "print(\"total:\", total)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A for loop can be exited altogether using the break keyword. This code sums elements\n",
    "of the list until a 5 is reached:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "sequence = [1, 2, 0, 4, 6, 5, 2, 1]\n",
    "total_until_5 = 0\n",
    "\n",
    "for value in sequence:\n",
    "    if value == 5:\n",
    "        break\n",
    "    total_until_5 += value"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As we will see in more detail, if the elements in the collection or iterator are sequences\n",
    "(tuples or lists, say), they can be conveniently unpacked into variables in the for loop\n",
    "statement:"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {},
   "source": [
    "for a, b, c in iterator:\n",
    "    # do something"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### **Exercise**:\n",
    "\n",
    "Given an array of ints and a target int, return the number of specified ints in the argument that are found in the array. \n",
    "\n",
    "eg. array_count([1, 9, 9, 3, 9], 9) → 3"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def array_count(my_array, target):\n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "array_count([1, 9, 9, 3, 9], 9)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# **range**\n",
    "\n",
    "The range function produces a list of evenly-spaced integers:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "range(5)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This can be seen more readily if we cast the range object to a list:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "list(range(5))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "list(range(0, 10, 3))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As you can see, range produces integers up to but not including the endpoint. A common\n",
    "use of range is for iterating through sequences by index:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "seq = [1, 2, 3, 4]\n",
    "for i in range(len(seq)):\n",
    "    val = seq[i]\n",
    "    print(val)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Range in Python 3 behaves the same as xrange in Python 2 - it returns an iterator that generates integers one by one rather than generating all of them up-front and storing them in a (potentially very large) list. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exercise: \n",
    "\n",
    "Generate a range of numbers from 100 to 200 at intervals of 5:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### **Exercise:** \n",
    "\n",
    "Given an array of ints, return True if the sequence.. 1, 2, 3, .. appears in the array somewhere.\n",
    "\n",
    "array123([1, 1, 2, 3, 1]) → True"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def array123(nums):\n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "array123([1, 2, 3])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "array123([1, 1, 2, 3, 1])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### **Exercise**: \n",
    "\n",
    "Write function to creates a histogram for * characters for each int from a given list of integers in the format below."
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {},
   "source": [
    "eg histogram([2,4])\n",
    "\n",
    "returns:\n",
    "**\n",
    "****"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "def histogram( items ):  \n",
    "    \n",
    "histogram([2, 3, 6, 10, 5, 2])  "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Often when working with sequences, we would also like to retain the positional index. Instead of defining our own counter variable and incrementing it for each iteration, we have a built-in function enumerate() for this task. Enumerate() method adds a counter to a sequence which we can then iterate over."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "seq = [1, 2, 3, 4]\n",
    "seq = [1, 2, 3, 4]\n",
    "for i, j in enumerate(seq):\n",
    "    print(i, j)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### **Exercise:** \n",
    "\n",
    "Write a function using enumerate() which when given an array of ints, and a target number, return the position of this target number in the array, otherwise it returns -1.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def find_position_in_array(items, target):\n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "seq = [1, 2, 3, 4]\n",
    "find_position_in_array(seq, 3)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# **while loops**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A while loop specifies a condition and a block of code that is to be executed until the\n",
    "condition evaluates to False or the loop is explicitly ended with break:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x = 256\n",
    "total = 0\n",
    "while x > 0:\n",
    "    if total > 500:\n",
    "        break\n",
    "    total += x\n",
    "    x = x // 2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# **pass**\n",
    "\n",
    "pass is the “no-op” statement in Python. It can be used in blocks where no action is to\n",
    "be taken; it is only required because Python uses whitespace to delimit blocks:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "if x < 0:\n",
    "    print('negative!')\n",
    "elif x == 0:\n",
    "    # TODO: put something smart here\n",
    "    pass\n",
    "else:\n",
    "    print('positive!')\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "It’s common to use pass as a place-holder in code while working on a new piece of\n",
    "functionality:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def f(x, y, z):\n",
    "    # TODO: implement this function!\n",
    "    pass"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# **Strings**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Many people use Python for its powerful and flexible built-in string processing capabilities. **You can write string literals using either single quotes ' or double quotes \"**:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = 'one way of writing a string'\n",
    "b = \"another way\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "For multiline strings with line breaks, you can use triple quotes, either ''' or \"\"\":"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "c = \"\"\"\n",
    "This is a longer string that\n",
    "spans multiple lines\n",
    "\"\"\"\n",
    "c"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Many Python objects can be converted to a string using the str function:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = 5.6\n",
    "s = str(a)\n",
    "s"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Strings are a sequence of characters and therefore can be treated like other sequences,\n",
    "such as lists and tuples:\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "s = 'python'\n",
    "list(s)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The backslash character \\ is an escape character, meaning that it is used to specify\n",
    "special characters like newline \\n or unicode characters. To write a string literal with backslashes, you need to escape them:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "s = '12\\445'\n",
    "print(s)\n",
    "print(type(s))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "s = '12\\\\445'\n",
    "print(s)\n",
    "print(type(s))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If you have a string with a lot of backslashes and no special characters, you might find this a bit annoying. Fortunately you can preface the leading quote of the string with **r** which means that the characters should be interpreted as is:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "s = r'this\\has\\no\\special\\characters'\n",
    "print(s)\n",
    "print(type(s))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Adding two strings together concatenates them and produces a new string:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = 'this is the first half '\n",
    "b = 'and this is the second half'\n",
    "a + b"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "String templating or formatting is another useful topic. The number of ways to do\n",
    "so has expanded with the advent of Python 3, here I will briefly describe the mechanics\n",
    "of one of the main interfaces. \n",
    "\n",
    "Strings with a % followed by one or more format characters is a target for inserting a value into that string (this is quite similar to the printf function in C). \n",
    "\n",
    "As an example, consider this string:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "template = '%.2f %s are worth $%d'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In this string, %s means to format an argument as a string, %.2f a number with 2 decimal places, and %d an integer. To substitute arguments for these format parameters, use the binary operator % with a tuple of values:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "template % (4.5560, 'Argentine Pesos', 1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "String formatting is a broad topic; there are multiple methods and numerous options\n",
    "and tweaks available to control how values are formatted in the resulting string. \n",
    "\n",
    "To learn more, I recommend you seek out more information on the web."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Almost all built-in Python constructs and any class defining the \\__nonzero__ magic method which have a True or False interpretation in an if statement:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = [1, 2, 3]\n",
    "if a:\n",
    "    print('I found something!')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "b = []\n",
    "if not b:\n",
    "    print('Empty!')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Most objects in Python have a notion of true- or falseness. For example, empty sequences (lists, dicts, tuples, etc.) are treated as False if used in control flow (as above with the empty list b). \n",
    "\n",
    "You can see exactly what boolean value an object coerces to by invoking bool on it:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "bool([]), bool([1, 2, 3])\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "bool('Hello world!'), bool('')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "bool(0), bool(1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# **Type casting**\n",
    "\n",
    "The str, bool, int and float types are also functions which can be used to cast values\n",
    "to those types:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "s = '3.14159'\n",
    "type(s)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fval = float(s)\n",
    "type(fval)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# **None**\n",
    "\n",
    "None is the Python null value type. If a function does not explicitly return a value, it implicitly returns None."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = None\n",
    "a is None"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "b = 5; b is not None"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "None is also a common default value for optional function arguments:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def add_and_maybe_multiply(a, b, c=None):\n",
    "    result = a + b\n",
    "    if c is not None:\n",
    "        result = result * c\n",
    "    return result"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# **Dates and times**\n",
    "\n",
    "The built-in Python datetime module provides datetime, date, and time types.\n",
    "\n",
    "The\n",
    "datetime type as you may imagine combines the information stored in date and time\n",
    "and is the most commonly used:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from datetime import datetime, date, time\n",
    "\n",
    "dt = datetime(2020, 2, 24, 20, 30, 21)\n",
    "dt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "dt.day"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "dt.minute"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Given a datetime instance, you can extract the equivalent date and time objects by\n",
    "calling methods on the datetime of the same name:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "dt.date()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "dt.time()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The strftime method formats a datetime as a string:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "dt.strftime('%m/%d/%Y %H:%M')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Strings can be converted (parsed) into datetime objects using the strptime function:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "datetime.strptime('20201031', '%Y%m%d')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "When aggregating or otherwise grouping time series data, it will occasionally be useful\n",
    "to replace fields of a series of datetimes, for example replacing the minute and second\n",
    "fields with zero, producing a new object:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(dt)\n",
    "\n",
    "print(dt.replace(minute=0, second=0))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The difference of two datetime objects produces a datetime.timedelta type:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "dt2 = datetime(2019, 2, 24, 20, 30, 21)\n",
    "delta = dt - dt2\n",
    "print(type(delta))\n",
    "print(delta)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Adding a timedelta to a datetime produces a new shifted datetime:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "dt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "dt + delta"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exercise: \n",
    "\n",
    "Write a script to output exactly how long ago Christmas last year was."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "diff = \n",
    "diff"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(diff.days)\n",
    "print(diff.seconds)\n",
    "print(diff.microseconds)\n",
    "print(diff.total_seconds())\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# **Mutable and immutable objects**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Most objects in Python are mutable, such as lists, dicts, NumPy arrays, or most userdefined types (classes). This means that the object or values that they contain can be modified. Others, like strings and tuples, are immutable:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a_tuple = (3, 5, (4, 5))\n",
    "print(a_tuple[1])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a_tuple[1] = 'four'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = 'this is a string'\n",
    "a[10] = 'f'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# **Imports**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In Python a module is simply a .py file containing function and variable definitions\n",
    "along with such things imported from other .py files. Suppose that we had the following\n",
    "module:"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {},
   "source": [
    "# some_module.py\n",
    "PI = 3.14159\n",
    "\n",
    "def f(x):\n",
    "    return x + 2\n",
    "\n",
    "def g(a, b):\n",
    "    return a + b"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If we wanted to access the variables and functions defined in some_module.py, from\n",
    "another file in the same directory we could do:"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {},
   "source": [
    "import some_module \n",
    "\n",
    "result = some_module.f(5)\n",
    "pi = some_module.PI"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Or equivalently:"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {},
   "source": [
    "from some_module import f, g, PI\n",
    "result = g(5, PI)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "By using the **as** keyword you can give imports different variable names:"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {},
   "source": [
    "import some_module as sm\n",
    "from some_module import PI as pi, g as gf\n",
    "\n",
    "r1 = sm.f(pi)\n",
    "r2 = gf(6, pi)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.3"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
